package com.jvyou.mybatis.builder.parser;

import com.jvyou.mybatis.builder.config.*;
import com.jvyou.mybatis.utils.string.StringUtils;

import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 橘柚
 * @version 1.0-SNAPSHOT
 * @Date 2024/7/19 10:49
 * @Description XML 配置空间
 */
public class XmlConfigContext {

    // 配置上下文的唯一实例
    private static volatile XmlConfigContext instance;

    // 标志位 instanceCreated 确保只有第一次实例化时是合法的
    private static boolean instanceCreated = false;

    // 环境配置
    private final Map<String, EnvironmentConfig> environments = new HashMap<>();
    // 插件配置
    private final List<PluginConfig> plugins = new ArrayList<>();
    // 映射器配置
    private final List<String> mappers = new ArrayList<>();
    // 映射器包配置
    private final List<String> packages = new ArrayList<>();
    // classpath 下的 xml Mapper
    private final List<String> resources = new ArrayList<>();
    // 外部文件 xml Mapper
    private final List<String> files = new ArrayList<>();
    // init 配置
    private InitConfig initConfig = new InitConfig();

    /**
     * 添加外部 XML 映射文件
     *
     * @param file 外部 XML 映射文件
     */
    public void addFile(String file) {
        files.add(file);
    }

    /**
     * 获取外部 XML 映射文件列表
     *
     * @return 外部 XML 映射文件列表
     */
    public List<String> getFiles() {
        return files;
    }

    /**
     * 添加类路径下的 XML 映射文件
     *
     * @param resource 类路径下的 XML 映射文件
     */
    public void addResource(String resource) {
        resources.add(resource);
    }

    /**
     * 获取类路径下的 XML 映射文件列表
     *
     * @return 类路径下的 XML 映射文件列表
     */
    public List<String> getResources() {
        return resources;
    }


    /**
     * 添加包配置
     *
     * @param packageConfig 包配置
     */
    public void addPackage(String packageConfig) {
        packages.add(packageConfig);
    }

    /**
     * 获取包配置
     *
     * @return Mapper 包列表
     */
    public List<String> getPackages() {
        return packages;
    }

    /**
     * 添加映射器配置
     *
     * @param mapper 映射器配置
     */
    public void addMapper(String mapper) {
        mappers.add(mapper);
    }

    /**
     * 获取映射器接口列表
     *
     * @return Mapper 列表
     */
    public List<String> getMappers() {
        return mappers;
    }

    /**
     * 添加插件配置
     *
     * @param plugin 插件配置
     */
    public void addPlugin(PluginConfig plugin) {
        plugins.add(plugin);
    }

    /**
     * 获取插件配置列表
     *
     * @return 插件配置列表
     */
    public List<PluginConfig> getPlugins() {
        return plugins;
    }


    /**
     * 返回XML配置的第一个环境下的事务管理器
     *
     * @return TransactionManagerConfig
     */
    public TransactionManagerConfig getTransactionManagerConfig() {
        // 返回第一个环境配置下的事务管理器
        if (environments.isEmpty()) {
            return null;
        }
        return environments.values().iterator().next().getTransactionManager();
    }

    /**
     * 获取指定环境下的事务管理器配置
     *
     * @param id 环境 ID
     * @return TransactionManagerConfig
     */
    public TransactionManagerConfig getTransactionManagerConfig(String id) {
        return environments.get(id).getTransactionManager();
    }

    /**
     * 默认返回环境列表中的第一个数据源，只配置了一个数据源使用
     *
     * @return DataSourceConfig
     */
    public DataSourceConfig getDataSourceConfig() {
        // 返回第一个环境配置下的数据源
        if (environments.isEmpty()) {
            return null;
        }
        return environments.values().iterator().next().getDataSource();
    }

    /**
     * 获取指定环境下的数据源配置
     *
     * @param id 环境 ID
     * @return DataSourceConfig
     */
    public DataSourceConfig getDataSourceConfig(String id) {
        if (StringUtils.isEmpty(id)) {
            return getDataSourceConfig();
        }
        return environments.get(id).getDataSource();
    }

    /**
     * 向配置上下环境文添加环境配置
     *
     * @param environment 环境配置
     */
    public void addEnvironment(EnvironmentConfig environment) {
        environments.put(environment.getId(), environment);
    }

    /**
     * 获取指定 ID 的环境配置
     *
     * @param id 环境 ID
     * @return EnvironmentConfig
     */
    public EnvironmentConfig getEnvironment(String id) {
        return environments.get(id);
    }

    /**
     * 获取环境配置
     *
     * @return 环境配置
     */
    public Map<String, EnvironmentConfig> getEnvironments() {
        return environments;
    }


    public String getInitConfigProperty(String key) {
        return initConfig.getProperty(key);
    }

    public void putInitConfigProperty(String key, String value) {
        initConfig.putProperty(key, value);
    }

    public InitConfig getInitConfig() {
        return initConfig;
    }

    public void setInitConfig(InitConfig initConfig) {
        this.initConfig = initConfig;
    }

    private XmlConfigContext() {
        if (instanceCreated) {
            throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
        }
        instanceCreated = true;
    }

    /**
     * 单例模式，获取 XmlConfigParser 唯一的实例，保证了线程安全，获取实例会自动解析 XML 配置
     *
     * @return XmlConfigParser 实例
     */
    public static XmlConfigContext getInstance() {
        if (instance == null) {
            synchronized (XmlConfigParser.class) {
                if (instance == null) {
                    instance = new XmlConfigContext();
                }
            }
        }
        return instance;
    }

    /**
     * 防止在反序列化时创建另一个实例,当一个对象被反序列化时，Java虚拟机会检查该对象所属的类是否定义了readResolve方法。如果定义了这个方法，反序列化过程就会调用这个方法来获取返回的对象
     *
     * @return 当前的实例对象
     * @throws ObjectStreamException 对象流异常
     */
    protected Object readResolve() throws ObjectStreamException {
        return getInstance();
    }

}
